use std::ops;

struct Foo;
struct Bar;

#[derive(Debug)]
struct FooBar;

#[derive(Debug)]
struct BarFoo;

// `std::ops::Add` trait 用来指明 `+` 的功能，这里我们实现 `Add<Bar>`，它是用于
// 把对象和 `Bar` 类型的右操作数（RHS）加起来的 `trait`。
// 下面的代码块实现了 `Foo + Bar = FooBar` 这样的运算。
impl ops::Add<Bar> for Foo {
    type Output = FooBar;

    fn add(self, _rhs: Bar) -> FooBar {
        println!("> Foo.add(Bar) was called");

        FooBar
    }
}

// 通过颠倒类型，我们实现了不服从交换律的加法。
// 这里我们实现 `Add<Foo>`，它是用于把对象和 `Foo` 类型的右操作数加起来的 trait。
// 下面的代码块实现了 `Bar + Foo = BarFoo` 这样的运算。
impl ops::Add<Foo> for Bar {
    type Output = BarFoo;

    fn add(self, _rhs: Foo) -> BarFoo {
        println!("> Bar.add(Foo) was called");

        BarFoo
    }
}

#[derive(Debug,PartialEq)]
struct Centimeters(u64);
struct Meter(u64);

struct Length(u64);

impl From<Centimeters> for Length{
    fn from(value: Centimeters) -> Self {
        Self(value.0)
    }
}

impl From<Meter> for Length {
    fn from(value: Meter) -> Self {
        Self(value.0 * 100)
    }
}

impl From<Length> for Centimeters {
    fn from(value: Length) -> Self {
        Self(value.0)
    }
}

impl From<Length> for Meter {
    fn from(value: Length) -> Self {
        Self(value.0 / 100)
    }
}

impl ops::Add<Length> for Length {
    type Output = Self;

    fn add(self, _rhs: Length) -> Self::Output {
        Self(self.0 + _rhs.0)
    }
}


#[test]
fn main() {
    println!("Foo + Bar = {:?}", Foo + Bar);
    println!("Bar + Foo = {:?}", Bar + Foo);

    // 这里有个问题。 开发场景下很多情况，需要对变量多次引用运算之类的操作，应该怎么处理
    // 可能可以通过后续的clone来解决这个问题
    // 也可以抽象出一个trait类处理这个情况

    let res = Length::from(Meter(1)) + Length::from(Centimeters(10));
    assert_eq!(Centimeters(110), res.into());
    
    let res = Length::from(Centimeters(10)) + Length::from(Meter(1));
    assert_eq!(Centimeters(110), res.into());
}
